/** @file profile.c
 *
 * @author cameris camerisdump@gmail.com
 */

#include "profile.h"
#include "uart.h"
#include "terminal.h"
#include "lcd.h"
#include <avr/eeprom.h>

#define MAX_PROFILES 3
#define WRITTEN 0x55
#define START_ADDRESS 0x00

#define STATUS_LENGTH 18
#define MAX_BAUD_LENGTH 7

/** @name string representation of uart parameters
 * @{ */
const __flash uint8_t str_2400[] = "2400";
const __flash uint8_t str_4800[] = "4800";
const __flash uint8_t str_9600[] = "9600";
const __flash uint8_t str_19200[] = "19200";
const __flash uint8_t str_38400[] = "38400";
const __flash uint8_t str_57600[] = "57600";
const __flash uint8_t str_115200[] = "115200";

const __flash uint8_t * const __flash baud_label[MAX_BAUD] = {
	str_2400,
	str_4800,
	str_9600,
	str_19200,
	str_38400,
	str_57600,
	str_115200
};

const __flash uint8_t databit_label[] = {
	'5', '6', '7', '8'
};

const __flash uint8_t parity_label[] = {
	'N', '?', 'E', 'O'
};

const __flash uint8_t stopbit_label[] = {
	'1', '2'
};
/**@} */


/** brief currently active profile */
struct profile curprofile = {10,{BAUD_9600,3,0,0},0,0,0,0,0};

/** @brief initialize profile */
void profile_init(void)
{ /* {{{ */
	lcd_set_bl(curprofile.backlight);

	uart_set_parameters(&curprofile.uart);

	term_set_autowrap(curprofile.autowrap);
	term_set_local_echo(curprofile.localecho);
	term_set_newlinemode(curprofile.newline);
	term_set_show_control_chars(curprofile.showcontrol);
	term_set_screenmode(curprofile.screen);
} /* }}} */

/** @brief print profile in last line */
void profile_print_status(void)
{ /* {{{ */
	uint8_t n = 0;
	uint8_t strbuf[STATUS_LENGTH];
	const __flash uint8_t *pnt = baud_label[curprofile.uart.baud];

	for (uint8_t i = 0; i < STATUS_LENGTH-1; i++) {
		strbuf[i] = ' ';
	}
	strbuf[STATUS_LENGTH-1] = '\0';

	while (*pnt) {
		n++;
		pnt++;
	}
	if (n > MAX_BAUD_LENGTH) n = 0;
	else n = MAX_BAUD_LENGTH - n;

	pnt = baud_label[curprofile.uart.baud];
	while (*pnt) {
		strbuf[n++] = *pnt;
		pnt++;
	}

	strbuf[n] = ' ';
	strbuf[++n] = databit_label[curprofile.uart.databits];
	strbuf[++n] = parity_label[curprofile.uart.parity];
	strbuf[++n] = stopbit_label[curprofile.uart.stopbits];
	n += 2;
	if (curprofile.localecho) strbuf[n] = 'E';
	n++;
	if (curprofile.autowrap) strbuf[n] = 'W';
	n++;
	if (curprofile.newline) strbuf[n] = 'N';
	n++;
	if (curprofile.showcontrol) strbuf[n] = 'C';
	n++;
	if (curprofile.bell) strbuf[n] = 'B';

	term_status_line(strbuf);
} /* }}} */

/** @brief load profile, but does not initialize it
 *
 * loads a profile from EEPROM if available. profile_init() should
 * be called after after successful loading to make changes.
 * @param num profile number, starting at 0
 * @return 1 if everthing went fine, 0 otherwise */
uint8_t profile_load(uint_fast8_t num)
{ /* {{{ */
	uint16_t address;
	uint8_t written;

	if (num >= MAX_PROFILES) return 0;

	address = START_ADDRESS + num*(sizeof(struct profile)+1);

	eeprom_busy_wait();
	written = eeprom_read_byte((uint8_t *)address);

	if (written != WRITTEN) return 0;

	eeprom_busy_wait();
	eeprom_read_block((void *) &curprofile, (void *) address+1, sizeof(struct profile));

	return 1;
} /* }}} */

/** @brief save profile
 *
 * save a profile to EEPROM, overwrites existing
 * @param num profile number, starting at 0 */
void profile_save(uint_fast8_t num)
{ /* {{{ */
	uint16_t address;

	if (num >= MAX_PROFILES) return;

	address = START_ADDRESS + num*(sizeof(struct profile)+1);

	eeprom_busy_wait();
	eeprom_update_byte((uint8_t *)address, WRITTEN);

	eeprom_busy_wait();
	eeprom_update_block((void *) &curprofile, (void *) address+1, sizeof(struct profile));
} /* }}} */

/* vim:set foldmethod=marker: */
